package com.ncepu.thumb.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ncepu.thumb.constant.ThumbConstant;
import com.ncepu.thumb.exception.BusinessException;
import com.ncepu.thumb.exception.ErrorCode;
import com.ncepu.thumb.model.dto.DoThumbRequest;
import com.ncepu.thumb.model.entity.Blog;
import com.ncepu.thumb.model.entity.Thumb;
import com.ncepu.thumb.model.entity.User;
import com.ncepu.thumb.service.BlogService;
import com.ncepu.thumb.service.ThumbService;
import com.ncepu.thumb.mapper.ThumbMapper;
import com.ncepu.thumb.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.concurrent.TimeUnit;

/**
* @author 14563
* @description 针对表【thumb】的数据库操作Service实现
* @createDate 2025-05-10 21:18:30
*/
@Service("thumbServiceDB")
@Slf4j
@RequiredArgsConstructor
public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb>
    implements ThumbService{

    private final BlogService blogService;
    private final TransactionTemplate transactionTemplate;
    private final UserService userService;
    private final RedissonClient redisson;
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public Boolean doThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) {
        if(doThumbRequest == null || doThumbRequest.getBlogId() == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }
        User loginUser = userService.getLoginUser(request);
        if(loginUser == null){
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
        }
        String lockKey = "lock:thumb:" + loginUser.getId();
        RLock lock = redisson.getLock(lockKey);
        try {
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                return transactionTemplate.execute(status -> {
                    Long blogId = doThumbRequest.getBlogId();
//                    boolean existsed = this.lambdaQuery()
//                            .eq(Thumb::getBlogId, blogId)
//                            .eq(Thumb::getUserId, loginUser.getId())
//                            .exists();
                    // 从redis中获取用户是否点赞的信息，如果存在，表示已经点赞
                    Boolean existsed = this.hasThumb(blogId, loginUser.getId());
                    if (existsed) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "用户已点赞");
                    }
                    boolean update = blogService.lambdaUpdate()
                            .eq(Blog::getId, blogId)
                            .setSql("thumbCount = thumbCount + 1")
                            .update();

                    Thumb thumb = new Thumb();
                    thumb.setUserId(loginUser.getId());
                    thumb.setBlogId(blogId);
                    boolean success = update && this.save(thumb);
                    if(success) {
                        // 将点赞信息保存到redis中
                        redisTemplate.opsForZSet().add(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId(), blogId.toString(), System.currentTimeMillis());
//                        redisTemplate.opsForHash().put(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId(), blogId.toString(), thumb.getId());
                    }
                    return success;
                });
            } else {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "系统繁忙, 请稍后再试");
            }
        }catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取锁失败");
        }finally {
            if(lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public Boolean undoThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) {
        if(doThumbRequest == null || doThumbRequest.getBlogId() == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }
        User loginUser = userService.getLoginUser(request);
        if(loginUser == null){
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
        }
        String lockKey = "lock:thumb:" + loginUser.getId();
        RLock lock = redisson.getLock(lockKey);
        try {
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                return transactionTemplate.execute(status -> {
                    Long blogId = doThumbRequest.getBlogId();
//                    Thumb thumb = this.lambdaQuery()
//                            .eq(Thumb::getBlogId, blogId)
//                            .eq(Thumb::getUserId, loginUser.getId())
//                            .one();
                    Boolean hasThumb = this.hasThumb(blogId, loginUser.getId());
//                    Object thumbIdObj = redisTemplate.opsForHash().get(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId(), blogId.toString());
                    if (!hasThumb) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "用户未点赞");
                    }
//                    Long thumbId = Long.valueOf(thumbIdObj.toString());
                    boolean update = blogService.lambdaUpdate()
                            .eq(Blog::getId, blogId)
                            .setSql("thumbCount = thumbCount - 1")
                            .update();
                    QueryWrapper<Thumb> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("blogId", blogId)
                            .eq("userId", loginUser.getId());
                    boolean success = update && this.remove(queryWrapper);
                    if(success) {
                        redisTemplate.opsForZSet().remove(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId(), blogId.toString());
//                        redisTemplate.opsForHash().delete(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId(), blogId.toString());
                    }
                    return success;
                });
            } else {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "系统繁忙, 请稍后再试");
            }
        }catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取锁失败");
        }finally {
            if(lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public Boolean hasThumb(Long blogId, Long userId) {
//        Boolean hasKeyInRedis = redisTemplate.opsForHash().hasKey(ThumbConstant.USER_THUMB_KEY_PREFIX + userId, blogId.toString());
//        if(!hasKeyInRedis) {
//            Thumb thumb = this.lambdaQuery()
//                    .eq(Thumb::getUserId, userId)
//                    .eq(Thumb::getBlogId, blogId)
//                    .one();
//            if(thumb != null) {
//                redisTemplate.opsForHash().put(ThumbConstant.USER_THUMB_KEY_PREFIX + userId, blogId.toString(), thumb.getId());
//            }
//            return thumb != null;
//        }
//        return hasKeyInRedis;
        Double score = redisTemplate.opsForZSet().score(ThumbConstant.USER_THUMB_KEY_PREFIX + userId, blogId);
        return score != null;
//        return redisTemplate.opsForHash().hasKey(ThumbConstant.USER_THUMB_KEY_PREFIX + userId, blogId.toString());
    }
}




